#-*- coding: utf-8 -*-



class Player(object):
    def __init__(self, name, actions):
        self.name = name
        self.actions = actions

    def __str__(self):
        return "Player: Name: '{0}', Actions: {1}".format(self.name, self.actions)



class Event(object):
    def __init__(self, name, payoffs):
        self.name = name
        self.payoffs = payoffs

    def __str__(self):
        return "Event: Name: '{0}', Payoffs: {1}".format(self.name, self.payoffs)

        

class Game(object):
    def __init__(self, name, players=None, events=None, eventmatrix=None):
        self.name = name
        self.players = players or []
        self.events = events or []
        self.eventmatrix = eventmatrix or []
        
    @staticmethod
    def fillmatrix(remaining_players, cur_index, cur_mult, flatmatrix):
        """Create and fill a k-dimensional tensor of payoffs/rewards.

        Arguments:
        remaining_players -- the list of yet-to-be-processed Players, initially <Game>.players
        cur_index -- carried along, terminates in the 'real' index in flatmatrix
        cur_mult -- carried along, describes the dimensionality of the currently processed Player
        flatmatrix -- the flat list of events from which the tensor is created

        Returns: a len(<Game>.players)-dimensional list of Integers
        """
        if not remaining_players:  # base case
            return flatmatrix[cur_index]
        else:  # recursion step
            m = [Game.fillmatrix(remaining_players[1:],
                   cur_index+cur_mult*i,
                   cur_mult*len(remaining_players[0].actions),
                   flatmatrix)
                 for i,a in enumerate(remaining_players[0].actions)]
            return m

    def setMatrix(self, flatmatrix):
        if not self.players:
            raise AttributeError
        self.eventmatrix = Game.fillmatrix(self.players, 0, 1, flatmatrix)

    def getMatrixEntry(self, coordinates, m=None):
        if not m: m=self.eventmatrix
        if len(coordinates) == 1:
            return m[coordinates[0]]
        else:
            return self.getMatrixEntry(coordinates[1:], m[coordinates[0]])

    # returns a PrettyPrint of an actionprofile, naming players and their respective actions
    def verboseActionProfile(self, profile):
        return "{0} at:\n  {1}".format(self.events[self.getMatrixEntry(profile)].name, ["{0}: {1}".format(self.players[i].name, self.players[i].actions[a]) for i,a in enumerate(profile)])

    # checks if a given coordinate in the event matrix is a NASH EQUILIBRIUM
    def isNashEquilibrium(self, coordinates):
        for i in range(len(coordinates)):
            p1 = self.events[self.getMatrixEntry(coordinates)].payoffs[i]
            for other in range(len(self.players[i].actions)):
                if self.events[self.getMatrixEntry(coordinates[:i] + [other] + coordinates[i+1:])].payoffs[i] > p1:
                    return False
        return True
                

    def __str__(self):
        return """GAME:
    Name: {0},
    Players:
        {1},
    Events:
        {2},
    PayoffMatrix: ({4})
        {3}""".format(self.name,
                      "\n        ".join([str(p) for p in self.players]),
                      "\n        ".join(str(e) for e in self.events),
                      self.eventmatrix,
                      ''.join(['[%s]'%p.name for p in self.players]))

    

    
